package com.clp.protocol.iec104.client.master_state;

import com.clp.protocol.iec104.apdu.Apdu;
import com.clp.protocol.iec104.apdu.apci.UCtrlArea;
import com.clp.protocol.iec104.client.MasterImpl;
import com.clp.protocol.iec104.client.async.MasterPromise;
import com.clp.protocol.iec104.client.async.send_apdu.SendStartDtVRes;
import com.clp.protocol.iec104.client.async.send_apdu.SendStopDtVRes;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.Vector;
import java.util.concurrent.TimeUnit;

/**
 * 启动传输、停止传输过程主站状态
 */
@Slf4j
public class DtMasterState extends AbstractMasterState {

    private enum State {
        NONE,
        START_DT_V,
        START_DT_C,
        STOP_DT_V,
        STOP_DT_C;
    }

    private volatile State state;
    private volatile Date lastStartDtVTime;
    private volatile Date lastStartDtCTime;
    private volatile Date lastStopDtVTime;
    private volatile Date lastStopDtCTime;
    private final int timeoutSeconds;

    private final Vector<MasterPromise<SendStartDtVRes>> startDtPromises;
    private final Vector<MasterPromise<SendStopDtVRes>> stopDtPromises;

    protected DtMasterState(MasterStateManager stateManager, int timeoutSeconds) {
        super(stateManager);
        this.timeoutSeconds = timeoutSeconds;
        this.startDtPromises = new Vector<>();
        this.stopDtPromises = new Vector<>();
        this.reset();
    }

    @Override
    public void reset() {
        this.state = State.NONE;
        this.lastStartDtVTime = new Date();
        this.lastStartDtCTime = new Date();
        this.lastStopDtVTime = new Date();
        this.lastStopDtCTime = new Date();
    }

    @Override
    public Apdu updateBySending(Apdu apdu) {
        if (apdu == null || !apdu.isUType()) return apdu;
        UCtrlArea ctrlArea = apdu.castToUType().getUApci().getCtrlArea();
        switch (ctrlArea.getUCtrlType()) {
            case U_START_DT_V:
                // 第一次发送或重新发送
                if (state == State.NONE) {
                    lastStartDtVTime = new Date();
                    state = State.START_DT_V;
                    // 发送成功
                    startDtPromises.forEach(promise -> promise.getRes().setSendSuccess(true));
                } else {
                    startDtPromises.forEach(promise -> {
                        // 发送失败、接收失败
                        promise.getRes().setSendSuccess(false).setRecvAck(false);
                        promise.setFailure(new RuntimeException("期望状态：" + State.NONE + ", 当前状态：" + state));
                    });
                    startDtPromises.clear();
                    apdu = null;
                }
                break;
            case U_STOP_DT_V:
                if (state == State.START_DT_C) {
                    lastStartDtVTime = new Date();
                    state = State.STOP_DT_V;
                    // 发送成功
                    startDtPromises.forEach(promise -> promise.getRes().setSendSuccess(true));
                } else {
                    stopDtPromises.forEach(promise -> {
                        // 发送失败、接收失败
                        promise.getRes().setSendSuccess(false).setRecvAck(false);
                        promise.setFailure(new RuntimeException("期望状态：" + State.START_DT_C + ", 当前状态：" + state));
                    });
                    stopDtPromises.clear();
                    apdu = null;
                }
                break;
        }
        return apdu;
    }

    @Override
    public Apdu updateByRecving(Apdu apdu) {
        if (apdu == null || !apdu.isUType()) return apdu;
        switch (apdu.castToUType().getUApci().getCtrlArea().getUCtrlType()) {
            case U_START_DT_C:
                if (state == State.START_DT_V) {
                    lastStartDtCTime = new Date();
                    state = State.START_DT_C;
                    startDtPromises.forEach(promise -> {
                        // 接收成功
                        promise.getRes().setRecvAck(true);
                        promise.setSuccess();
                    });
                    startDtPromises.clear();
                }
                break;
            case U_STOP_DT_C:
                if (state == State.STOP_DT_V) {
                    lastStopDtCTime = new Date();
                    state = State.STOP_DT_C;
                    stopDtPromises.forEach(promise -> {
                        promise.getRes().setRecvAck(true);
                        promise.setSuccess();
                    });
                    stopDtPromises.clear();
                    state = State.NONE;
                }
                break;
        }
        return apdu;
    }

    @Override
    public void startMonitorTask() {
        tryStopMonitorTask();

        scheduledFuture = scheduleAtFixedRate(() -> {

            Date nowTime = new Date();
            switch (state) {
                case NONE:
                    break;
                case START_DT_V: // 发送启动传输激活，进入该状态，处理超时情况
                    if (nowTime.getTime() - lastStartDtVTime.getTime() >= timeoutSeconds * 1000L) {
                        startDtPromises.forEach(promise -> {
                            promise.getRes().setRecvAck(false);
                            promise.setFailure(new RuntimeException("Timeout ..."));
                        });
                        startDtPromises.clear();
                        log.error("启动传输激活超时，即将重连...");
                        ((MasterImpl) stateManager.getMaster()).closeChannel(false);
                    }
                    break;
                case START_DT_C: // 接收到启动传输确认，无异常情况
                    break;
                case STOP_DT_V: // 发送停止传输激活，处理超时情况
                    if (nowTime.getTime() - lastStopDtVTime.getTime() >= timeoutSeconds * 1000L) {
                        stopDtPromises.forEach(promise -> {
                            promise.getRes().setRecvAck(false);
                            promise.setFailure(new RuntimeException("Timeout ..."));
                        });
                        stopDtPromises.clear();
                        log.error("停止传输激活超时，即将重连...");
                        ((MasterImpl) stateManager.getMaster()).closeChannel(false);
                    }
                    break;
                case STOP_DT_C: // 接收到停止传输确认，无异常情况会发生
                    break;
            }

        }, 0, 1, TimeUnit.SECONDS);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <V> MasterPromise<V> register(MasterPromise<V> sendPromise) {
        if (sendPromise == null || sendPromise.getRes() == null) return sendPromise;
        if (sendPromise.getRes() instanceof SendStartDtVRes) {
            startDtPromises.add(((MasterPromise<SendStartDtVRes>) sendPromise));
            return null;
        }
        if (sendPromise.getRes() instanceof SendStopDtVRes) {
            stopDtPromises.add(((MasterPromise<SendStopDtVRes>) sendPromise));
            return null;
        }
        return sendPromise;
    }

    public boolean isStartedDt() {
        return state == State.START_DT_C;
    }
}
